#pragma once
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

static const int gcap = 5;
using namespace SemMouble;
using namespace MutexMouble;

template<class T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        :_rq(cap),
         _cap(cap),
         _blank_sem(cap),
         _p_step(0),
         _data_sem(0),
         _c_step(0)
    {}

    void Equeue(const T &in)
    {
        //生产者
        _blank_sem.P();
        {
            LockGuard LockGuard(_p_mutex);
            _rq[_p_step] = in;
            _p_step = (_p_step + 1) % _cap;
        }
        _data_sem.V();
    }

    void Pop(T *out)
    {
        //消费者
        _data_sem.P();
        {
            LockGuard LockGuard(_c_mutex);
            *out = _rq[_c_step];
            _c_step = (_c_step + 1) % _cap;
        }
        _blank_sem.V();
    }

    ~RingQueue() {}
private:
    std::vector<T> _rq;
    int _cap;

    Sem _blank_sem;//生产者
    int _p_step;
    Sem _data_sem; //消费者
    int _c_step;

    // 维护多生产多消费
    Mutex _p_mutex;
    Mutex _c_mutex;
};